package com.cloud.base.aopLimit;

import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @Program: cloud-pay
 * @Description:
 * @Version: v1.0.0
 * @Author: hantianyang
 * Modification History:
 * Date             Author      Version     Description
 * -------------------------------------------------------------
 * 2021/11/22  20:24     韩天阳      v1.0.0      创建
 */
@Aspect
@Component
public class LimitAop {

    //多线程-线程共享
    private ConcurrentHashMap<String, RateLimiter> rateLimiters = new ConcurrentHashMap();

    //    private RateLimiter rateLimiter = RateLimiter.create(2.0);
    //拦截所有的请求，查看是否存在注解
    //也可以拦截某个包，但是需要判断每个类上面是否存在注解，但是拦截注解比较简单
    @Around(value = "@annotation(com.cloud.base.aopLimit.LimitInterface)")
    public Object around(ProceedingJoinPoint joinPoint) {

        //可以使用限流
        try {
            //获取拦截的方法名称
            Signature sig = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) sig;
            //获取方法上的LimitInterface注解
            LimitInterface declaredAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LimitInterface.class);
            //获取到注解的name；
            String name = declaredAnnotation.name();
            //获取到注解的token；
            double token = declaredAnnotation.token();

            RateLimiter rateLimiter = rateLimiters.get(name);
            if (rateLimiter == null) {
                rateLimiter = RateLimiter.create(token);
                rateLimiters.put(name, rateLimiter);
            }
            //限流的使用
            boolean result = rateLimiter.tryAcquire();
            if (!result) {
                return "当前访问人数过多，请稍后重试";
            }

            System.out.println("环绕通知开始");
            Object proceed = joinPoint.proceed();
            System.out.println("环绕通知结束");

            //proceed就是方法的返回值
            return proceed;
        } catch (Throwable throwable) {
            return "系统错误";
        }
    }

    //前置通知与后置通知不能拦截请求，环绕通知可以拦截通过 joinPoint.proceed();执行目标方法
    @Before(value = "@annotation(com.cloud.base.aopLimit.LimitInterface)")
    public void before() {
        System.out.println("前置通知");
    }

    @AfterReturning(value = "@annotation(com.cloud.base.aopLimit.LimitInterface)")
    public void afterReturning() {
        System.out.println("后置通知");
    }
}
